package wsdc.app.main.v1;

import jakarta.annotation.PostConstruct;
import lombok.Getter;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

@Service
public class CertificateService {

    String fileRoot = "d:\\cert\\certs";

    @Autowired
    CertConfig certConfig;

    @PostConstruct
    public void init() {
        Security.addProvider(new BouncyCastleProvider());
        fileRoot = certConfig.getDir();
    }

    /**
     * 创建CA 兼容安卓
     */
    public CertificateBundle createCa(String commonName, String organization, String country, int validityYears) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        X500Name issuer = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.CN, commonName).addRDN(BCStyle.O, organization).addRDN(BCStyle.C, country).addRDN(BCStyle.OU, "Android Compatible CA").build();

        // Android建议CA证书有效期不超过10年
        int androidValidYears = Math.min(validityYears, 10);
        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date();
        Date notAfter = new Date(notBefore.getTime() + androidValidYears * 365L * 24 * 60 * 60 * 1000);

        X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, issuer, keyPair.getPublic());

        // 设置基本约束扩展（CA证书）- critical
        certificateBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));

        // 设置密钥用法扩展（更完整的设置）- critical
        certificateBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign | KeyUsage.digitalSignature));

        // 设置增强密钥用法扩展
        certificateBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth}));

        // 设置主体密钥标识符
        JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
        certificateBuilder.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(keyPair.getPublic()));

        // 设置颁发者密钥标识符
        certificateBuilder.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(keyPair.getPublic()));

        // 添加Netscape Cert Type扩展（提高兼容性）
        try {
            certificateBuilder.addExtension(new ASN1ObjectIdentifier("2.16.840.1.113730.1.1"), false, new DERBitString(new byte[]{(byte) 0xC0})); // SSL CA | S/MIME CA
        } catch (Exception e) {
            System.out.println("Warning: Could not add Netscape Cert Type extension");
        }

        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").setProvider("BC").build(keyPair.getPrivate());

        X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);
        X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);

        return new CertificateBundle(certificate, keyPair.getPrivate());
    }

    /**
     * 从磁盘加载ca证书
     */
    public CertificateBundle loadCACertificateFromDisk(String certPath, String keyPath) throws Exception {
        // 读取证书
        String certContent = readPEMFile(certPath);
        X509Certificate certificate = parseCertificate(certContent);

        // 读取私钥
        String keyContent = readPEMFile(keyPath);
        PrivateKey privateKey = parsePrivateKey(keyContent);

        return new CertificateBundle(certificate, privateKey);
    }

    /**
     * 读取PEM文件内容
     */
    public String readPEMFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (!line.startsWith("-----BEGIN") && !line.startsWith("-----END")) {
                    content.append(line);
                }
            }
        }
        return content.toString();
    }

    /**
     * 解析证书
     */
    public X509Certificate parseCertificate(String certContent) throws Exception {
        byte[] certBytes = java.util.Base64.getDecoder().decode(certContent);
        java.security.cert.CertificateFactory certificateFactory = java.security.cert.CertificateFactory.getInstance("X.509");
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(certBytes)) {
            return (X509Certificate) certificateFactory.generateCertificate(inputStream);
        }
    }

    /**
     * 解析私钥
     */
    public PrivateKey parsePrivateKey(String keyContent) throws Exception {
        byte[] keyBytes = java.util.Base64.getDecoder().decode(keyContent);
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
        java.security.spec.PKCS8EncodedKeySpec keySpec = new java.security.spec.PKCS8EncodedKeySpec(keyBytes);
        return keyFactory.generatePrivate(keySpec);
    }

    public PKCS12Bundle loadFromPKCS12(String pkcs12Path, String password) throws Exception {
        File pkcs12File = new File(pkcs12Path);
        if (!pkcs12File.exists()) {
            throw new FileNotFoundException("PKCS12文件不存在: " + pkcs12Path);
        }

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream(pkcs12File)) {
            keyStore.load(fis, password.toCharArray());
        }

        // 查找私钥条目
        String alias = null;
        Enumeration<String> aliases = keyStore.aliases();
        while (aliases.hasMoreElements()) {
            String currentAlias = aliases.nextElement();
            if (keyStore.isKeyEntry(currentAlias)) {
                alias = currentAlias;
                break;
            }
        }

        if (alias == null) {
            throw new Exception("PKCS12文件中未找到私钥条目");
        }

        // 获取私钥
        Key key = keyStore.getKey(alias, password.toCharArray());
        if (!(key instanceof PrivateKey)) {
            throw new Exception("找到的密钥不是私钥");
        }
        PrivateKey privateKey = (PrivateKey) key;

        // 获取证书链
        java.security.cert.Certificate[] certChain = keyStore.getCertificateChain(alias);
        if (certChain == null || certChain.length == 0) {
            throw new Exception("未找到证书链");
        }

        X509Certificate certificate = (X509Certificate) certChain[0];
        X509Certificate[] caCertificates = new X509Certificate[certChain.length - 1];
        for (int i = 1; i < certChain.length; i++) {
            caCertificates[i - 1] = (X509Certificate) certChain[i];
        }

        return new PKCS12Bundle(certificate, privateKey, caCertificates, alias);
    }




    /**
     * 3. 根据CA证书生成SSL证书
     */
    public CertificateBundle createSsl(CertificateBundle caBundle, String commonName, String organization, String country, String[] sanDomains, int validityYears) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        X509Certificate caCert = caBundle.getCertificate();
        X500Name issuer = new X509CertificateHolder(caCert.getEncoded()).getSubject();

        X500Name subject = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.CN, commonName).addRDN(BCStyle.O, organization).addRDN(BCStyle.C, country).build();

        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date();
        Date notAfter = new Date(notBefore.getTime() + validityYears * 365L * 24 * 60 * 60 * 1000);

        X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic());

        // 设置基本约束扩展（非CA证书）
        certificateBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));

        // 设置密钥用法扩展
        certificateBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));

        // 设置增强密钥用法扩展
        certificateBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth}));

        // 设置主体密钥标识符
        JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
        certificateBuilder.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(keyPair.getPublic()));

        // 设置颁发者密钥标识符
        certificateBuilder.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(caCert));

        // 添加SAN扩展（Subject Alternative Name）
        if (sanDomains != null && sanDomains.length > 0) {
            GeneralName[] generalNames = new GeneralName[sanDomains.length];
            for (int i = 0; i < sanDomains.length; i++) {
                generalNames[i] = new GeneralName(GeneralName.dNSName, sanDomains[i]);
            }
            GeneralNames subjectAltNames = new GeneralNames(generalNames);
            certificateBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
        }

        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").setProvider("BC").build(caBundle.getPrivateKey());

        X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);
        X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);

        return new CertificateBundle(certificate, keyPair.getPrivate());
    }

    /**
     *
     */
    public CertificateBundle createSslPkcs(CertificateBundle caBundle, String commonName, String organization, String country, String[] sanDomains, int validityYears, String password) throws Exception {
        // 生成SSL证书
        CertificateBundle sslBundle = createSsl(caBundle, commonName, organization, country, sanDomains, validityYears);

        // 保存为PKCS12格式文件（Tomcat可以直接使用）
        saveAsPKCS12WithChain(sslBundle.getCertificate(), sslBundle.getPrivateKey(), caBundle.getCertificate(),"tomcat-ssl.p12", password);

        return sslBundle;
    }


    /**
     * 创建泛域名
     */
    public CertificateBundle createSslWild(CertificateBundle caBundle, String commonName, String organization, String country, String[] sanDomains, String wildcardDomain, int validityYears, String password) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        X509Certificate caCert = caBundle.getCertificate();
        X500Name issuer = new X509CertificateHolder(caCert.getEncoded()).getSubject();

        X500Name subject = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.CN, commonName).addRDN(BCStyle.O, organization).addRDN(BCStyle.C, country).build();

        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date();
        Date notAfter = new Date(notBefore.getTime() + validityYears * 365L * 24 * 60 * 60 * 1000);

        X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic());

        // 设置基本约束扩展（非CA证书）
        certificateBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));

        // 设置密钥用法扩展
        certificateBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));

        // 设置增强密钥用法扩展
        certificateBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth}));

        // 设置主体密钥标识符
        JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
        certificateBuilder.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(keyPair.getPublic()));

        // 设置颁发者密钥标识符
        certificateBuilder.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(caCert));

        // 构建SAN扩展，包含泛域名
        List<GeneralName> generalNamesList = new ArrayList<>();

        // 添加普通域名
        if (sanDomains != null && sanDomains.length > 0) {
            for (String domain : sanDomains) {
                generalNamesList.add(new GeneralName(GeneralName.dNSName, domain));
            }
        }

        // 添加泛域名（通配符域名）
        if (wildcardDomain != null && !wildcardDomain.isEmpty()) {
            generalNamesList.add(new GeneralName(GeneralName.dNSName, wildcardDomain));
            // 如果泛域名不是以*开头，自动添加通配符版本
            if (!wildcardDomain.startsWith("*.")) {
                generalNamesList.add(new GeneralName(GeneralName.dNSName, "*." + wildcardDomain));
            }
        }

        // 如果有SAN条目，则添加SAN扩展
        if (!generalNamesList.isEmpty()) {
            GeneralName[] generalNames = generalNamesList.toArray(new GeneralName[0]);
            GeneralNames subjectAltNames = new GeneralNames(generalNames);
            certificateBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
        }

        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").setProvider("BC").build(caBundle.getPrivateKey());

        X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);
        X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);

        return new CertificateBundle(certificate, keyPair.getPrivate());
    }

    /**
     * 将证书保存为PEM格式文件
     */
    public void saveCertificateAsPEM(X509Certificate certificate, String filename) throws Exception {
        File certDir = new File(fileRoot);
        if (!certDir.exists()) {
            certDir.mkdirs();
        }

        try (FileWriter writer = new FileWriter(new File(certDir, filename))) {
            writer.write("-----BEGIN CERTIFICATE-----\n");
            writer.write(java.util.Base64.getEncoder().encodeToString(certificate.getEncoded()));
            writer.write("\n-----END CERTIFICATE-----\n");
        }
    }

    /**
     * 将私钥保存为PEM格式文件
     */
    public void savePrivateKeyAsPEM(PrivateKey privateKey, String filename) throws Exception {
        File certDir = new File(fileRoot);
        if (!certDir.exists()) {
            certDir.mkdirs();
        }

        try (FileWriter writer = new FileWriter(new File(certDir, filename))) {
            writer.write("-----BEGIN PRIVATE KEY-----\n");
            writer.write(java.util.Base64.getEncoder().encodeToString(privateKey.getEncoded()));
            writer.write("\n-----END PRIVATE KEY-----\n");
        }
    }

    public void saveAsPKCS12WithChain(X509Certificate certificate, PrivateKey privateKey, X509Certificate caCertificate, String filename, String password) throws Exception {
        // 创建完整的证书链，顺序很重要：终端证书在前，CA证书在后
        Certificate[] chain = {certificate, caCertificate};

        // 创建KeyStore
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(null, null);

        // 设置密钥条目，包含完整证书链
        keyStore.setKeyEntry("tomcat", privateKey, password.toCharArray(), chain);

        // 保存到文件
        File outputFile = new File(fileRoot+"/" + filename);
        // 确保父目录存在
        outputFile.getParentFile().mkdirs();

        try (FileOutputStream fos = new FileOutputStream(outputFile)) {
            keyStore.store(fos, password.toCharArray());
        }
    }

    /**
     * PKCS12文件内容包装类
     */
    @Getter
    public static class PKCS12Bundle {
        private final X509Certificate certificate;
        private final PrivateKey privateKey;
        private final X509Certificate[] caCertificates;
        private final String alias;

        public PKCS12Bundle(X509Certificate certificate, PrivateKey privateKey, X509Certificate[] caCertificates, String alias) {
            this.certificate = certificate;
            this.privateKey = privateKey;
            this.caCertificates = caCertificates != null ? caCertificates : new X509Certificate[0];
            this.alias = alias;
        }

        public X509Certificate getCertificate() {
            return certificate;
        }

        public PrivateKey getPrivateKey() {
            return privateKey;
        }

        public X509Certificate[] getCaCertificates() {
            return caCertificates;
        }

        public String getAlias() {
            return alias;
        }

        public java.security.cert.Certificate[] getCertificateChain() {
            java.security.cert.Certificate[] chain = new java.security.cert.Certificate[caCertificates.length + 1];
            chain[0] = certificate;
            System.arraycopy(caCertificates, 0, chain, 1, caCertificates.length);
            return chain;
        }
    }

    /**
     * 证书和私钥的包装类
     */
    public static class CertificateBundle {
        private final X509Certificate certificate;
        private final PrivateKey privateKey;

        public CertificateBundle(X509Certificate certificate, PrivateKey privateKey) {
            this.certificate = certificate;
            this.privateKey = privateKey;
        }

        public X509Certificate getCertificate() {
            return certificate;
        }

        public PrivateKey getPrivateKey() {
            return privateKey;
        }
    }
}
